Restructure resolve/lockfile ops
authorAlex Crichton <alex@alexcrichton.com>
Thu, 23 Oct 2014 05:18:49 +0000 (22:18 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 27 Oct 2014 19:40:23 +0000 (12:40 -0700)
Move functionality from cargo_fetch and cargo_generate_lockfile into dedicated
lockfile/resolve modules. The plan is to expand the resolve module significantly
to deal with the lockfile that's loaded.

src/cargo/ops/cargo_compile.rs
src/cargo/ops/cargo_fetch.rs
src/cargo/ops/cargo_generate_lockfile.rs
src/cargo/ops/lockfile.rs [new file with mode: 0644]
src/cargo/ops/mod.rs
src/cargo/ops/resolve.rs [new file with mode: 0644]

index feff4fc5ebec253af511f48889783a0d6994dea0..ef4464751813c4f3033fa4efb98763960ca8e1f8 100644 (file)
@@ -90,7 +90,7 @@ pub fn compile_pkg(package: &Package, options: &mut CompileOptions)
 
         // First, resolve the package's *listed* dependencies, as well as
         // downloading and updating all remotes and such.
-        try!(ops::resolve_and_fetch(&mut registry, package));
+        try!(ops::resolve_pkg(&mut registry, package));
 
         // Second, resolve with precisely what we're doing. Filter out
         // transitive dependencies if necessary, specify features, handle
index e4581f627b9060a38689d392a48bf36d547eb830..73d52a3ab1e63750643b587ec74a28355793c5f9 100644 (file)
@@ -16,34 +16,6 @@ pub fn fetch(manifest_path: &Path,
 
     let mut config = try!(Config::new(shell, None, None));
     let mut registry = PackageRegistry::new(&mut config);
-    try!(resolve_and_fetch(&mut registry, &package));
+    try!(ops::resolve_pkg(&mut registry, &package));
     Ok(())
 }
-
-/// Finds all the packages required to compile the specified `Package`,
-/// and loads them in the `PackageRegistry`.
-///
-/// Also write the `Cargo.lock` file with the results.
-pub fn resolve_and_fetch(registry: &mut PackageRegistry, package: &Package)
-                         -> CargoResult<Resolve> {
-    let _p = profile::start("resolve and fetch...");
-
-    let lockfile = package.get_manifest_path().dir_path().join("Cargo.lock");
-    let source_id = package.get_package_id().get_source_id();
-    let previous_resolve = try!(ops::load_lockfile(&lockfile, source_id));
-    let sources = match previous_resolve {
-        Some(ref r) => r.iter().map(|p| p.get_source_id().clone()).collect(),
-        None => vec![package.get_package_id().get_source_id().clone()],
-    };
-    try!(registry.add_sources(sources.as_slice()));
-
-    let mut resolved = try!(resolver::resolve(package.get_summary(),
-                                              resolver::ResolveEverything,
-                                              registry));
-    match previous_resolve {
-        Some(ref prev) => resolved.copy_metadata(prev),
-        None => {}
-    }
-    try!(ops::write_resolve(package, &resolved));
-    Ok(resolved)
-}
index 6d518380b96c152a9ed1b4c971df3e864f74648a..f789c3360963682aeab7ae888a2adcccdcd31db6 100644 (file)
@@ -4,13 +4,14 @@ use std::io::File;
 use serialize::{Encodable, Decodable};
 use toml::{mod, Encoder};
 
+use core::PackageId;
 use core::registry::PackageRegistry;
 use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
-use core::PackageId;
+use ops;
 use sources::{PathSource};
 use util::config::{Config};
-use util::{CargoResult, human};
 use util::toml as cargo_toml;
+use util::{CargoResult, human};
 
 pub struct UpdateOptions<'a> {
     pub shell: &'a mut MultiShell<'a>,
@@ -26,14 +27,9 @@ pub fn generate_lockfile(manifest_path: &Path,
     try!(source.update());
     let package = try!(source.get_root_package());
     let mut config = try!(Config::new(shell, None, None));
-
-    let resolve = {
-        let mut registry = PackageRegistry::new(&mut config);
-        try!(resolver::resolve(package.get_summary(),
-                               resolver::ResolveEverything,
-                               &mut registry))
-    };
-    try!(write_resolve(&package, &resolve));
+    let mut registry = PackageRegistry::new(&mut config);
+    let resolve = try!(ops::resolve_with_previous(&mut registry, &package, None));
+    try!(ops::write_pkg_lockfile(&package, &resolve));
     Ok(())
 }
 
@@ -43,9 +39,7 @@ pub fn update_lockfile(manifest_path: &Path,
     try!(source.update());
     let package = try!(source.get_root_package());
 
-    let lockfile = package.get_root().join("Cargo.lock");
-    let source_id = package.get_package_id().get_source_id();
-    let previous_resolve = match try!(load_lockfile(&lockfile, source_id)) {
+    let previous_resolve = match try!(ops::load_pkg_lockfile(&package)) {
         Some(resolve) => resolve,
         None => return Err(human("A Cargo.lock must exist before it is updated"))
     };
@@ -89,7 +83,7 @@ pub fn update_lockfile(manifest_path: &Path,
                                              resolver::ResolveEverything,
                                              &mut registry));
     resolve.copy_metadata(&previous_resolve);
-    try!(write_resolve(&package, &resolve));
+    try!(ops::write_pkg_lockfile(&package, &resolve));
     return Ok(());
 
     fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
@@ -107,82 +101,3 @@ pub fn update_lockfile(manifest_path: &Path,
         }
     }
 }
-
-pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
-    // If there is no lockfile, return none.
-    let mut f = match File::open(path) {
-        Ok(f) => f,
-        Err(_) => return Ok(None)
-    };
-
-    let s = try!(f.read_to_string());
-
-    let table = toml::Table(try!(cargo_toml::parse(s.as_slice(), path)));
-    let mut d = toml::Decoder::new(table);
-    let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
-    Ok(Some(try!(v.to_resolve(sid))))
-}
-
-pub fn write_resolve(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
-    let loc = pkg.get_root().join("Cargo.lock");
-
-    let mut e = Encoder::new();
-    resolve.encode(&mut e).unwrap();
-
-    let mut out = String::new();
-
-    // Note that we do not use e.toml.to_string() as we want to control the
-    // exact format the toml is in to ensure pretty diffs between updates to the
-    // lockfile.
-    let root = e.toml.find(&"root".to_string()).unwrap();
-
-    out.push_str("[root]\n");
-    emit_package(root.as_table().unwrap(), &mut out);
-
-    let deps = e.toml.find(&"package".to_string()).unwrap().as_slice().unwrap();
-    for dep in deps.iter() {
-        let dep = dep.as_table().unwrap();
-
-        out.push_str("[[package]]\n");
-        emit_package(dep, &mut out);
-    }
-
-    match e.toml.find(&"metadata".to_string()) {
-        Some(metadata) => {
-            out.push_str("[metadata]\n");
-            out.push_str(metadata.to_string().as_slice());
-        }
-        None => {}
-    }
-
-    try!(File::create(&loc).write_str(out.as_slice()));
-    Ok(())
-}
-
-fn emit_package(dep: &toml::TomlTable, out: &mut String) {
-    out.push_str(format!("name = {}\n", lookup(dep, "name")).as_slice());
-    out.push_str(format!("version = {}\n", lookup(dep, "version")).as_slice());
-
-    if dep.contains_key(&"source".to_string()) {
-        out.push_str(format!("source = {}\n", lookup(dep, "source")).as_slice());
-    }
-
-    if let Some(ref s) = dep.find(&"dependencies".to_string()) {
-        let slice = s.as_slice().unwrap();
-
-        if !slice.is_empty() {
-            out.push_str("dependencies = [\n");
-
-            for child in s.as_slice().unwrap().iter() {
-                out.push_str(format!(" {},\n", child).as_slice());
-            }
-
-            out.push_str("]\n");
-        }
-        out.push_str("\n");
-    }
-}
-
-fn lookup<'a>(table: &'a toml::TomlTable, key: &str) -> &'a toml::Value {
-    table.find(&key.to_string()).expect(format!("Didn't find {}", key).as_slice())
-}
diff --git a/src/cargo/ops/lockfile.rs b/src/cargo/ops/lockfile.rs
new file mode 100644 (file)
index 0000000..24c60cd
--- /dev/null
@@ -0,0 +1,101 @@
+use std::collections::HashSet;
+use std::io::File;
+
+use serialize::{Encodable, Decodable};
+use toml::{mod, Encoder};
+
+use core::registry::PackageRegistry;
+use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
+use core::PackageId;
+use sources::{PathSource};
+use util::config::{Config};
+use util::{CargoResult, human};
+use util::toml as cargo_toml;
+
+pub fn load_pkg_lockfile(pkg: &Package) -> CargoResult<Option<Resolve>> {
+    let lockfile = pkg.get_manifest_path().dir_path().join("Cargo.lock");
+    let source_id = pkg.get_package_id().get_source_id();
+    load_lockfile(&lockfile, source_id)
+}
+
+pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
+    // If there is no lockfile, return none.
+    let mut f = match File::open(path) {
+        Ok(f) => f,
+        Err(_) => return Ok(None)
+    };
+
+    let s = try!(f.read_to_string());
+
+    let table = toml::Table(try!(cargo_toml::parse(s.as_slice(), path)));
+    let mut d = toml::Decoder::new(table);
+    let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
+    Ok(Some(try!(v.to_resolve(sid))))
+}
+
+pub fn write_pkg_lockfile(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
+    let loc = pkg.get_root().join("Cargo.lock");
+    write_lockfile(&loc, resolve)
+}
+
+pub fn write_lockfile(dst: &Path, resolve: &Resolve) -> CargoResult<()> {
+    let mut e = Encoder::new();
+    resolve.encode(&mut e).unwrap();
+
+    let mut out = String::new();
+
+    // Note that we do not use e.toml.to_string() as we want to control the
+    // exact format the toml is in to ensure pretty diffs between updates to the
+    // lockfile.
+    let root = e.toml.find(&"root".to_string()).unwrap();
+
+    out.push_str("[root]\n");
+    emit_package(root.as_table().unwrap(), &mut out);
+
+    let deps = e.toml.find(&"package".to_string()).unwrap().as_slice().unwrap();
+    for dep in deps.iter() {
+        let dep = dep.as_table().unwrap();
+
+        out.push_str("[[package]]\n");
+        emit_package(dep, &mut out);
+    }
+
+    match e.toml.find(&"metadata".to_string()) {
+        Some(metadata) => {
+            out.push_str("[metadata]\n");
+            out.push_str(metadata.to_string().as_slice());
+        }
+        None => {}
+    }
+
+    try!(File::create(dst).write_str(out.as_slice()));
+    Ok(())
+}
+
+fn emit_package(dep: &toml::TomlTable, out: &mut String) {
+    out.push_str(format!("name = {}\n", lookup(dep, "name")).as_slice());
+    out.push_str(format!("version = {}\n", lookup(dep, "version")).as_slice());
+
+    if dep.contains_key(&"source".to_string()) {
+        out.push_str(format!("source = {}\n", lookup(dep, "source")).as_slice());
+    }
+
+    if let Some(ref s) = dep.find(&"dependencies".to_string()) {
+        let slice = s.as_slice().unwrap();
+
+        if !slice.is_empty() {
+            out.push_str("dependencies = [\n");
+
+            for child in s.as_slice().unwrap().iter() {
+                out.push_str(format!(" {},\n", child).as_slice());
+            }
+
+            out.push_str("]\n");
+        }
+        out.push_str("\n");
+    }
+}
+
+fn lookup<'a>(table: &'a toml::TomlTable, key: &str) -> &'a toml::Value {
+    table.find(&key.to_string()).expect(format!("Didn't find {}", key).as_slice())
+}
index 64e811bbe2a6d31d57238889942901ad4d7fde9b..5176ce75f29fc3831024e242cae519f526ca4eaa 100644 (file)
@@ -8,27 +8,32 @@ pub use self::cargo_rustc::{PlatformPlugin, PlatformPluginAndTarget};
 pub use self::cargo_run::run;
 pub use self::cargo_new::{new, NewOptions};
 pub use self::cargo_doc::{doc, DocOptions};
-pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
-pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
+pub use self::cargo_generate_lockfile::{generate_lockfile};
+pub use self::cargo_generate_lockfile::{update_lockfile};
 pub use self::cargo_generate_lockfile::UpdateOptions;
+pub use self::lockfile::{load_lockfile, load_pkg_lockfile};
+pub use self::lockfile::{write_lockfile, write_pkg_lockfile};
 pub use self::cargo_test::{run_tests, run_benches, TestOptions};
 pub use self::cargo_package::package;
 pub use self::registry::{publish, registry_configuration, RegistryConfig};
 pub use self::registry::{registry_login, http_proxy, http_handle};
 pub use self::registry::{modify_owners, yank};
-pub use self::cargo_fetch::{fetch, resolve_and_fetch};
+pub use self::cargo_fetch::{fetch};
 pub use self::cargo_pkgid::pkgid;
+pub use self::resolve::{resolve_pkg, resolve_with_previous};
 
 mod cargo_clean;
 mod cargo_compile;
-mod cargo_read_manifest;
-mod cargo_rustc;
-mod cargo_run;
-mod cargo_new;
 mod cargo_doc;
+mod cargo_fetch;
 mod cargo_generate_lockfile;
-mod cargo_test;
+mod cargo_new;
 mod cargo_package;
-mod cargo_fetch;
 mod cargo_pkgid;
+mod cargo_read_manifest;
+mod cargo_run;
+mod cargo_rustc;
+mod cargo_test;
+mod lockfile;
 mod registry;
+mod resolve;
diff --git a/src/cargo/ops/resolve.rs b/src/cargo/ops/resolve.rs
new file mode 100644 (file)
index 0000000..c9ad81c
--- /dev/null
@@ -0,0 +1,56 @@
+use std::collections::HashMap;
+
+use semver::VersionReq;
+
+use core::{MultiShell, Package};
+use core::registry::PackageRegistry;
+use core::resolver::{mod, Resolve};
+use core::source::Source;
+use ops;
+use sources::PathSource;
+use util::{CargoResult, Config};
+use util::profile;
+
+/// Resolve all dependencies for the specified `package` using the previous
+/// lockfile as a guide if present.
+///
+/// This function will also generate a write the result of resolution as a new
+/// lockfile.
+pub fn resolve_pkg(registry: &mut PackageRegistry, package: &Package)
+                   -> CargoResult<Resolve> {
+    let prev = try!(ops::load_pkg_lockfile(package));
+    let resolve = try!(resolve_with_previous(registry, package, prev.as_ref()));
+    try!(ops::write_pkg_lockfile(package, &resolve));
+    Ok(resolve)
+}
+
+/// Resolve all dependencies for a package using an optional prevoius instance
+/// of resolve to guide the resolution process.
+///
+/// The previous resolve normally comes from a lockfile. This function does not
+/// read or write lockfiles from the filesystem.
+pub fn resolve_with_previous(registry: &mut PackageRegistry,
+                             package: &Package,
+                             previous: Option<&Resolve>)
+                             -> CargoResult<Resolve> {
+    let root = package.get_package_id().get_source_id().clone();
+    try!(registry.add_sources(&[root]));
+
+    match previous {
+        Some(r) => {
+            let v = r.iter().map(|p| p.get_source_id().clone())
+                     .collect::<Vec<_>>();
+            try!(registry.add_sources(v.as_slice()));
+        }
+        None => {}
+    };
+
+    let mut resolved = try!(resolver::resolve(package.get_summary(),
+                                              resolver::ResolveEverything,
+                                              registry));
+    match previous {
+        Some(r) => resolved.copy_metadata(previous),
+        None => {}
+    }
+    Ok(resolved)
+}